package utils

import (
	"context"
	"fmt"
	"net"
	"net/http"

	"go-micro.dev/v4"
	"go-micro.dev/v4/client"
	"gopkg.in/ini.v1"

	"gitee.com/go-micro-services/common"
	"github.com/go-micro/plugins/v4/registry/consul"
	opentracingTool "github.com/go-micro/plugins/v4/wrapper/trace/opentracing"
	"github.com/opentracing/opentracing-go"
	log "go-micro.dev/v4/logger"
	"go-micro.dev/v4/registry"

	"github.com/afex/hystrix-go/hystrix"
	"github.com/go-micro/plugins/v4/wrapper/select/roundrobin"
)

// 微服务micro客户端
var SrvClient client.Client
var ConsulAddr string
var ConsulReg registry.Registry
var TracerAddr string
var HystrixPort string
var CartServices string

// 读取通用配置
func initMicro(appConfig *ini.File) {
	// 1. 配置注册中心
	ConsulAddr = appConfig.Section("consul").Key("address").String()
	ConsulReg := consul.NewRegistry(
		registry.Addrs(ConsulAddr),
	)
	// 2. 配置链路追踪 jaeger
	TracerAddr = appConfig.Section("jaeger").Key("tracerAddr").String()
	// SetTracer()
	// 3. 配置熔断
	HystrixPort = appConfig.Section("hystrix").Key("hystrixPort").String()
	setHystrix()

	// 4. 获取服务
	CartServices = appConfig.Section("services").Key("cart").String()

	// 5. 创建服务
	srv := micro.NewService()
	srv.Init(
		micro.Name(AppName),
		micro.Version(AppVersion),
		micro.Registry(ConsulReg),
		// 绑定链路追踪
		micro.WrapHandler(opentracingTool.NewHandlerWrapper(opentracing.GlobalTracer())),
		// 添加熔断
		micro.WrapClient(NewClientHystrixWrapper()),
		// 添加负载均衡
		micro.WrapClient(roundrobin.NewClientWrapper()),
	)
	SrvClient = srv.Client() // 对外暴露
}

// 链路追踪配置
func SetTracer() (opentracing.Tracer, error) {
	tracer, closer, err := common.NewTracer(AppName, TracerAddr)
	if err != nil {
		log.Fatal(err)
	}
	defer closer.Close()
	return tracer, err
}

// 熔断器 设置
func setHystrix() {
	hystrixStreamHandler := hystrix.NewStreamHandler()
	hystrixStreamHandler.Start()
	go func() {
		// 启动端口
		err := http.ListenAndServe(net.JoinHostPort(AppZeroHost, HystrixPort), hystrixStreamHandler)
		if err != nil {
			log.Error(err)
		}
	}()
}

// 熔断器 type
type clientWrapper struct {
	client.Client
}

// 熔断器 Call
func (c *clientWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	return hystrix.Do(req.Service()+"."+req.Endpoint(), func() error {
		// run 正常执行
		fmt.Println(req.Service() + "." + req.Endpoint())
		return c.Client.Call(ctx, req, rsp, opts...)
	}, func(err error) error {
		fmt.Println(err)
		return err
	})
}

// 熔断器 Wrapper
func NewClientHystrixWrapper() client.Wrapper {
	return func(i client.Client) client.Client {
		return &clientWrapper{i}
	}
}
